import { ReactElement, ReactNode, useRef } from 'react'
import { useUpdateEffect } from 'ahooks'
import { createStore, StoreApi, useStore } from 'zustand'

import { createInitValue, Ctx, popupSlot } from './Ctx'
import { IValue, TMethods } from './interface'

export const Provider = (props: { yyy?: boolean; children: ReactNode }): ReactElement => {
  const { yyy, children } = props

  const methodsRef = useRef<Partial<TMethods>>({})
  const storeRef = useRef<StoreApi<IValue>>()
  if (!storeRef.current) {
    storeRef.current = createStore((...args): IValue => {
      const initValue = createInitValue(...args)
      const { zzz, ...rest } = initValue

      return {
        ...rest,
        yyy: !!yyy,
        zzz: (...a) => {
          return (methodsRef.current.zzz || zzz)(...a)
        },
      }
    })
  }
  const store = storeRef.current

  /* === example === */
  // 取值
  const xxx = useStore(store, v => v.xxx)
  const setState = useStore(store, v => v.setState)
  // 方法定义
  methodsRef.current.zzz = () => {
    setState({ xxx: xxx + 10 })
  }
  // 外部变更时异步更新
  useUpdateEffect(() => store.setState({ yyy: !!yyy }), [!!yyy])
  /* === example end === */

  return (
    <Ctx.Provider value={store}>
      {children}
      <popupSlot.Slot />
    </Ctx.Provider>
  )
}
